package com.ido.exception;

import com.alibaba.fastjson2.JSON;
import com.ido.exception.util.ExceptionUtil;
import com.ido.exception.util.IpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 全局异常捕捉
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    @ResponseBody
    public R<Object> delMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException e) {
        String ip = IpUtil.getIP(req);
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        Map<String, String> errMap = new HashMap<>();
        errors.forEach(objectError -> {
            errMap.put(((FieldError) objectError).getField(), objectError.getDefaultMessage());
        });
        log.error("全局异常-入参错误-ip【{}】：请求【{}】：错误信息【{}】", ip, req.getRequestURI(), JSON.toJSONString(errMap));
        Integer code = BaseResult.REQUEST_PARAMETER_ERROR.getCode();
        String msg = BaseResult.REQUEST_PARAMETER_ERROR.getMsg();
        if (ObjectUtils.isNotEmpty(errors) && StringUtils.isNotEmpty(errors.get(0).getDefaultMessage())) {
            msg = errors.get(0).getDefaultMessage();
        }
        return R.fail(code, msg);
    }

    @ExceptionHandler(value = {HttpMessageNotReadableException.class})
    @ResponseBody
    public R<Object> delMethodArgumentNotValidException(HttpServletRequest req, HttpMessageNotReadableException e) {
        String ip = IpUtil.getIP(req);
        log.error("全局异常-入参错误-ip【{}】：请求【{}】：错误信息【{}】", ip, req.getRequestURI(), e.getMessage());
        Integer code = BaseResult.REQUEST_PARAMETER_ERROR.getCode();
        String msg = BaseResult.REQUEST_PARAMETER_ERROR.getMsg();
        return R.fail(code, msg);
    }

    /**
     * 处理 @ModelAttribute + @Valid 表单提交校验
     */
    @ExceptionHandler(BindException.class)
    public R<Object> handleBindException(HttpServletRequest req, BindException e) {
        String ip = IpUtil.getIP(req);
        List<ObjectError> errors = e.getBindingResult().getAllErrors();
        Map<String, String> errMap = new HashMap<>();
        errors.forEach(objectError -> {
            errMap.put(((FieldError) objectError).getField(), objectError.getDefaultMessage());
        });
        log.error("全局异常-入参错误-ip【{}】：请求【{}】： 错误信息【{}】", ip, req.getRequestURI(), JSON.toJSONString(errMap));
        Integer code = BaseResult.REQUEST_PARAMETER_ERROR.getCode();
        String msg = BaseResult.REQUEST_PARAMETER_ERROR.getMsg();
        if (ObjectUtils.isNotEmpty(errors) && StringUtils.isNotEmpty(errors.get(0).getDefaultMessage())) {
            msg = errors.get(0).getDefaultMessage();
        }
        return R.fail(code, msg);
    }


    /**
     * 处理未知异常
     *
     * @param request   请求
     * @param exception 异常
     * @return 处理后的返回数据
     */
    @ExceptionHandler(Exception.class)
    public R handleException(HttpServletRequest request, Exception exception) {
        log.error(ExceptionUtil.getPrintStackTrace(exception, request));
        return R.fail();
    }

    /**
     * 处理业务异常
     *
     * @param request 请求
     * @param e       业务异常
     * @return 处理后的数据
     */
    @ExceptionHandler(value = BizException.class)
    public R handleBizException(HttpServletRequest request, BizException e) {
        log.error(ExceptionUtil.getPrintStackTrace(e, request));
        return R.fail(e);
    }

}
